package org.dromara.system.controller.api;

import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.PostDTO;
import org.dromara.common.core.enums.UserStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.api.domain.bo.RemoteUserBo;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.RoleDTO;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.domain.vo.*;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.*;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author: zhou shuai
 * @date: 2024/9/26 20:31
 * @version: v1
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/system/user")
public class SysUserApiController {

    private final ISysUserService userService;
    private final ISysPermissionService permissionService;
    private final ISysConfigService configService;
    private final ISysRoleService roleService;
    private final ISysDeptService deptService;
    private final ISysPostService postService;
    private final SysUserMapper userMapper;

    /**
     * 通过用户名查询用户信息
     *
     * @param userName 用户名
     * @param tenantId 租户id
     * @return 结果
     */
    @GetMapping("/info/byUserName")
    public R<LoginUser> getUserInfoByUserName(@RequestParam("userName") String userName, @RequestParam("tenantId") String tenantId) {
        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", userName);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", userName);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
        return R.ok(loginUser);
    }

    /**
     * 通过用户id查询用户信息
     *
     * @param userId   用户id
     * @param tenantId 租户id
     * @return 结果
     */
    @GetMapping("/info/byUserId")
    public R<LoginUser> getUserInfoByUserId(@RequestParam("userId") Long userId, @RequestParam("tenantId") String tenantId) {
        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoById(userId);
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", "");
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", sysUser.getUserName());
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
        return R.ok(loginUser);
    }

    /**
     * 通过手机号查询用户信息
     *
     * @param phoneNumber 手机号
     * @param tenantId    租户id
     * @return 结果
     */
    @GetMapping("/info/byPhoneNumber")
    public R<LoginUser> getUserInfoByPhoneNumber(@RequestParam("phoneNumber") String phoneNumber, @RequestParam("tenantId") String tenantId) {
        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phoneNumber));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", phoneNumber);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", phoneNumber);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
        return R.ok(loginUser);
    }

    /**
     * 通过邮箱查询用户信息
     *
     * @param email    邮箱
     * @param tenantId 租户id
     * @return 结果
     */
    @GetMapping("/info/byEmail")
    public R<LoginUser> getUserInfoByEmail(@RequestParam("email") String email, @RequestParam("tenantId") String tenantId) {
        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
            SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
            if (ObjectUtil.isNull(user)) {
                throw new UserException("user.not.exists", email);
            }
            if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
                throw new UserException("user.blocked", email);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(user);
        });
        return R.ok(loginUser);
    }

    /**
     * 通过openId查询用户信息
     *
     * @param openId
     * @return 结果
     */
    @GetMapping("/info/byOpenId")
    public R<XcxLoginUser> getUserInfoByOpenId(@RequestParam("openId") String openId) {
        // todo 自行实现 userService.selectUserByOpenid(openid);
        SysUser sysUser = new SysUser();
        if (ObjectUtil.isNull(sysUser)) {
            // todo 用户不存在 业务逻辑自行实现
        }
        if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
            // todo 用户已被停用 业务逻辑自行实现
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setUsername(sysUser.getUserName());
        loginUser.setNickname(sysUser.getNickName());
        loginUser.setUserType(sysUser.getUserType());
        loginUser.setOpenid(openId);
        return R.ok(loginUser);
    }

    /**
     * 注册用户信息
     *
     * @param remoteUserBo 用户信息
     * @return 结果
     */
    @PostMapping("/register")
    public R<Boolean> userRegister(@RequestBody RemoteUserBo remoteUserBo) {
        SysUserBo sysUserBo = MapstructUtils.convert(remoteUserBo, SysUserBo.class);
        String username = sysUserBo.getUserName();
        boolean exist = TenantHelper.dynamic(remoteUserBo.getTenantId(), () -> {
            if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
                throw new ServiceException("当前系统没有开启注册功能");
            }
            return userMapper.exists(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, sysUserBo.getUserName()));
        });
        if (exist) {
            throw new UserException("user.register.save.error", username);
        }
        return R.ok(userService.registerUser(sysUserBo, remoteUserBo.getTenantId()));
    }

    /**
     * 重置用户密码
     *
     * @param userId   用户id
     * @param password 用户密码
     * @return 结果
     */
    @PostMapping("/resetPas")
    public R<Boolean> resetUserPas(@RequestParam("userId") Long userId, @RequestParam("password") String password) {
        return R.ok(DataPermissionHelper.ignore(() -> userService.resetUserPwd(userId, BCrypt.hashpw(password)) > 0));
    }

    /**
     * 通过用户ID查询用户名
     *
     * @param userId 用户ID
     * @return 用户名
     */
    @GetMapping("/name/byUserId")
    public R<String> selectUserNameById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectUserNameById(userId));
    }

    /**
     * 通过用户ID查询用户昵称
     *
     * @param userId 用户ID
     * @return 用户昵称
     */
    @GetMapping("/nickName/byUserId")
    public R<String> selectNickNameById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectNickNameById(userId));
    }

    /**
     * 通过用户ID查询岗位名称
     *
     * @param userId 用户ID
     * @return 岗位名称
     */
    @GetMapping("/postName/byUserId")
    public R<String> selectPostNameById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectPostNameById(userId));
    }

    /**
     * 通过用户ID查询角色名称
     *
     * @param userId 用户ID
     * @return 角色名称
     */
    @GetMapping("/roleName/byUserId")
    public R<String> selectRoleNameById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectRoleNameById(userId));
    }

    /**
     * 通过用户ID集合查询用户昵称集合
     *
     * @param userIds 用户ID 多个用逗号隔开
     * @return 用户昵称集合
     */
    @GetMapping("/nickName/byUserIds")
    public R<String> selectNicknameByIds(@RequestParam("userIds") String userIds) {
        return R.ok(userService.selectNicknameByIds(userIds));
    }

    /**
     * 通过用户ID查询用户手机号
     *
     * @param userId 用户id
     * @return 用户手机号
     */
    @GetMapping("/phoneNumber/byUserId")
    public R<String> selectPhonenumberById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectPhonenumberById(userId));
    }

    /**
     * 通过用户ID查询用户邮箱
     *
     * @param userId 用户id
     * @return 用户邮箱
     */
    @GetMapping("/email/byUserId")
    public R<String> selectEmailById(@RequestParam("userId") Long userId) {
        return R.ok(userService.selectEmailById(userId));
    }

    /**
     * 更新用户信息
     *
     * @param userId 用户ID
     * @param ip     IP地址
     */
    @PostMapping("/save/login/info")
    public R<Void> recordLoginInfo(@RequestParam("userId") Long userId, @RequestParam("ip") String ip) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ip);
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(userId);
        DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
        return R.ok();
    }

    /**
     * 通过用户ID查询用户列表
     *
     * @param userIds 用户ids
     * @return 用户列表
     */
    @GetMapping("/list/byUserIds")
    public R<List<RemoteUserVo>> selectListByIds(@RequestParam("userIds") List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return R.ok(new ArrayList<>());
        }
        List<SysUserVo> list = userMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName,
                SysUser::getNickName, SysUser::getUserType, SysUser::getEmail,
                SysUser::getPhonenumber, SysUser::getSex, SysUser::getStatus,
                SysUser::getCreateTime)
            .eq(SysUser::getStatus, SystemConstants.NORMAL)
            .in(SysUser::getUserId, userIds));
        return R.ok(MapstructUtils.convert(list, RemoteUserVo.class));
    }

    /**
     * 通过角色ID查询用户ID
     *
     * @param roleIds 角色ids
     * @return 用户ids
     */
    @GetMapping("/userIdlist/byRoleIds")
    public R<List<Long>> selectUserIdsByRoleIds(@RequestParam("roleIds") List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return R.ok(new ArrayList<>());
        }
        return R.ok(userService.selectUserIdsByRoleIds(roleIds));
    }

    /**
     * 通过角色ID查询用户
     *
     * @param roleIds 角色ids
     * @return 用户
     */
    @GetMapping("/userlist/byRoleIds")
    public R<List<RemoteUserVo>> selectUsersByRoleIds(@RequestParam("roleIds") List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return R.ok(new ArrayList<>());
        }
        return R.ok(userService.selectUsersByRoleIds(roleIds));
    }

    /**
     * 通过部门ID查询用户
     *
     * @param deptIds 部门ids
     * @return 用户
     */
    @GetMapping("/userlist/byDeptIds")
    public R<List<RemoteUserVo>> selectUsersByDeptIds(@RequestParam("deptIds") List<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return R.ok(new ArrayList<>());
        }
        return R.ok(userService.selectUsersByDeptIds(deptIds));
    }

    /**
     * 通过岗位ID查询用户
     *
     * @param postIds 岗位ids
     * @return 用户
     */
    @GetMapping("/userlist/byPostIds")
    public R<List<RemoteUserVo>> selectUsersByPostIds(@RequestParam("postIds") List<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return R.ok(new ArrayList<>());
        }
        return R.ok(userService.selectUsersByPostIds(postIds));
    }

    /**
     * 根据用户 ID 列表查询用户名称映射关系
     *
     * @param userIds 用户 ID 列表
     * @return Map，其中 key 为用户 ID，value 为对应的用户名称
     */
    @GetMapping("/userName/byUserIds")
    public R<Map<Long, String>> selectUserNamesByIds(@RequestParam("userIds") List<Long> userIds) {
        return R.ok(userService.selectUserNamesByIds(userIds));
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 用户信息
     */
    @GetMapping("/getUserInfo")
    public R<LoginUser> getUserInfo() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        return R.ok(loginUser);
    }

    /**
     * 构建登录用户
     */
    private LoginUser buildLoginUser(SysUserVo userVo) {
        LoginUser loginUser = new LoginUser();
        Long userId = userVo.getUserId();
        loginUser.setTenantId(userVo.getTenantId());
        loginUser.setUserId(userId);
        loginUser.setDeptId(userVo.getDeptId());
        loginUser.setUsername(userVo.getUserName());
        loginUser.setNickname(userVo.getNickName());
        loginUser.setPassword(userVo.getPassword());
        loginUser.setUserType(userVo.getUserType());
        loginUser.setMenuPermission(permissionService.getMenuPermission(userId));
        loginUser.setRolePermission(permissionService.getRolePermission(userId));
        if (ObjectUtil.isNotNull(userVo.getDeptId())) {
            Opt<SysDeptVo> deptOpt = Opt.of(userVo.getDeptId()).map(deptService::selectDeptById);
            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
        }
        List<SysRoleVo> roles = roleService.selectRolesByUserId(userId);
        List<SysPostVo> posts = postService.selectPostsByUserId(userId);
        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
        loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class));
        return loginUser;
    }

}
